package tree;

import java.util.List;
import java.util.Map;

import lexer.Token;

/**
 * A tree factory interface. A Tree Factory is an abstract factory, that builds
 * up the AST and their subtrees. There is such a factory to guarantee a safe
 * build and a unique interface to have better control during the building
 * process.
 */
public interface TreeFactory {

	/**
	 * creates a node, representing an access on an array
	 * 
	 * @param token
	 *            for the identification of the array (array-name)
	 * @param leftHandAccess
	 *            Tree, representing the object graph you must follow to reach
	 *            the array
	 * @param indexList
	 *            list, containing the indices to access one field of the array,
	 *            e.g.: h.m.a[8][7][0] -> list(8,7,0)
	 * @return a node representing an array-access
	 */
	Tree makeArrayAccess(Token token, Tree leftHandAccess, List<Tree> indexList);

	/**
	 * Building method, represents an assignment
	 * 
	 * @param token
	 *            should contain TokenType.Assign as well as
	 *            TokenType.PLUSASSIGN, etc. pp.
	 * @param decl
	 *            declaration or usage of variable to which the assignment
	 *            should be
	 * @param expr
	 *            the expression, that should be assigned to the variable,
	 *            specified by decl
	 * @return a node representing an assignment
	 */
	Tree makeAssign(Token token, Tree decl, Tree expr);

	/**
	 * creates a node, representing a binary operation
	 * 
	 * @param token
	 *            Token to identify the operator
	 * @param left
	 *            the tree on the left-hand-side of the operator
	 * @param right
	 *            the tree on the right-hand-side of the operator
	 * @return a node representing a binary operation
	 */
	Tree makeBinOp(Token token, Tree left, Tree right);

	/**
	 * creates a node, representing a block of statements
	 * 
	 * @param trees
	 *            that correspond to the single statements
	 * @return a node representing a block of statements
	 */
	Tree makeBlock(Tree... trees);

	/**
	 * creates a node, representing a break-statement (in loops for example)
	 * 
	 * @param token
	 *            break-Token
	 * @return a node representing a break-statement
	 */
	Tree makeBreakStatement(Token token);

	/**
	 * creates a node, representing a catch-block
	 * 
	 * @param token
	 *            identification of the catch-block
	 * @param param
	 *            the condition (what should be caught)
	 * @param block
	 *            this should be executed, when the right exception is thrown
	 * @return a node representing a catch-block
	 */
	Tree makeCatch(Token token, Tree param, Tree block);

	/**
	 * Building method, represents the root node of a class declaration
	 * 
	 * @param token
	 *            the token that represents the name of the class
	 * @param numberOfType
	 *            unique number identifying a class or an interface
	 * @param extendsArr
	 *            array of reference-types, the class inherits from
	 * @param implementsArr
	 *            array of types, the class implements
	 * @param body
	 *            tree representing the body of a class-declaration
	 * @return the root node of a class-declaration
	 */
	Tree makeClassDecl(Token token, int numberOfType, Type[] extendsArr,
			Type[] implementsArr, Tree body);

	/**
	 * Building method, representing the creation and initialisation of an
	 * object (instance of a class)
	 * 
	 * @param token
	 *            Token representing the creation (TokenType.NEW)
	 * @param type
	 *            Type representing the class, the object is an instance of
	 * @param constructorParams
	 *            list of tree, representing the arguments for the constructor
	 *            being called
	 * @return node representing an object-creation
	 */
	Tree makeClassInstanceCreation(Token token, Type type,
			List<Tree> constructorParams);

	/**
	 * creates a node, representing a conditional clause
	 * 
	 * @param token
	 *            identification of the conditional clause
	 * @param cond
	 *            this is the condition
	 * @param trueExpr
	 *            this expression is executed, when cond evaluates to true
	 * @param falseExpr
	 *            this expression is executed, when cond evaluates to false
	 * @return a node representing a whole conditional clause
	 */
	Tree makeCond(Token token, Tree cond, Tree trueExpr, Tree falseExpr);

	/**
	 * creates a node, representing the declaration of a constructor
	 * 
	 * @param modifierList
	 *            list of modifiers, limiting the access or activating special
	 *            functions
	 * @param token
	 *            Token that usually represents the class-name
	 * @param throwsList
	 *            list of all exceptions that can be thrown
	 * @param params
	 *            parameters, that must be given to the constructor
	 * @param body
	 *            statement to be executed if the constructor is called
	 * @param localMethodVar
	 *            unique identification-number for method-declarations (for
	 *            analysis phases)
	 * @return a node representing the declaration of a constructor
	 */
	Tree makeConstructorDeclaration(List<Modifiers> modifierList, Token token,
			List<Type> throwsList, Tree params, Tree body, int localMethodVar);

	/**
	 * creates a node, representing the constructor invocation in another
	 * constructor, e.g. super(A)(8,9), this()
	 * 
	 * @param tok
	 *            identification of the constructor to call, TokenType.THIS or
	 *            TokenType.SUPER
	 * @param exprList
	 *            Tree, representing the list of arguments for the constructor
	 *            call
	 * @return a node representing the constructor invocation
	 */
	Tree makeConstructorInvokation(Token tok, Tree exprList);

	/**
	 * creates a node, representing a declaration
	 * 
	 * @param ident
	 *            token representation of the identifier being declared, should
	 *            contain TokenType.IDENT
	 * @param type
	 *            Type of the identifier being declared
	 * @param localVar
	 *            unique identification-number for local variables (for
	 *            analysis-phase)
	 * @return a node representing a declaration
	 */
	Tree makeDecl(Token ident, Type type, int localVar);

	/**
	 * creates a node, representing the dynamic type test, e.g.: a
	 * hasdynamictype B where a is an object, B is a class. The expression is
	 * evaluated to true if a is the variable for an object of class B. The type
	 * of a can also be C (B subclass of C). C is called static type, B dynamic
	 * type.
	 * 
	 * @param tok
	 *            token, representing the dynamic type test,
	 *            TokenType.HASDYNAMICTYPE
	 * @param left
	 *            tree, representing the object to test
	 * @param right
	 *            type, representing the class
	 * @return a node representing a dynamic-type test
	 */
	Tree makeDynamicTypeTest(Token tok, Tree left, Type right);

	/**
	 * creates a node, representing an empty statement. SO-Code: ";"
	 * 
	 * @param token
	 *            token, representing the empty statement
	 * @return subtree representing the empty statement
	 */
	Tree makeEmptyStatement(Token token);

	/**
	 * Building method, creates a node, representing an explicit cast to a
	 * specified type
	 * 
	 * @param token
	 *            Cast-Token
	 * @param toTyp
	 *            type that should be created
	 * @param expr
	 *            expression that should be casted
	 * @return a node, representing an explicit type-cast
	 */
	Tree makeExplicitTypeCast(Token token, Type toTyp, Tree expr);

	/**
	 * creates a subtree representing a field access. complex object graphs,
	 * e.g. a.b.c.d are represented by recursively created trees. Here a must be
	 * local-variable, this or super and d must be a field of the class C (when
	 * c has type C)
	 * 
	 * @param token
	 *            representing the field to access, here: d
	 * @param leftHandAccess
	 *            representing the object graph by recursively created trees,
	 *            here: a.b.c.
	 * @return a node representing a field access
	 */
	Tree makeFieldAccess(Token token, Tree leftHandAccess);

	/**
	 * creates a node, representing a for-loop
	 * 
	 * @param token
	 *            for-loop-token, TokenType.FOR
	 * @param forInit
	 *            initialising a start-parameter
	 * @param condExpr
	 *            the condition for the loop to run(normally containing the
	 *            forInit)
	 * @param forUpdate
	 *            expression that changes the parameter (normally earlier
	 *            forInit) in condExpr
	 * @param bodyStmt
	 *            this body has to be repeated as long as the condition allows
	 *            it
	 * @return a node representing a for-loop
	 */
	Tree makeForLoop(Token token, Tree forInit, Tree condExpr, Tree forUpdate,
			Tree bodyStmt);

	/**
	 * creates a node representing the declaration of a field (global variable)
	 * with the following parameters
	 * 
	 * @param modifierList
	 *            list of modifiers, specifying the field's accessibility
	 * @param ident
	 *            token representing the name of the field to declare
	 * @param type
	 *            type representing the type of the field to declare
	 * @param numberOfInstVar
	 *            unique number to identify a field exactly within is own class.
	 *            Also specifies the position of the field within the class (0
	 *            -> position 1)
	 * @return a node representing a field declaration
	 */
	Tree makeGlobalDecl(List<Modifiers> modifierList, Token ident, Type type,
			int numberOfInstVar);

	/**
	 * creates a node, representing a conditional without a false statement
	 * (true or do nothing)
	 * 
	 * @param token
	 *            If-Token
	 * @param cond
	 *            tree representing the condition
	 * @param trueStmt
	 *            case that happens if the condition is true
	 * @return a node representing an If-Conditional
	 */
	Tree makeIf(Token token, Tree cond, Tree trueStmt);

	/**
	 * creates a node, representing a conditional-statement with both, true and
	 * false case
	 * 
	 * @param token
	 *            IfElse-Token
	 * @param cond
	 *            tree representing the condition
	 * @param trueStmt
	 *            case that happens if the condition is true
	 * @param falseStmt
	 *            case that happens if the condition is false
	 * @return a node representing an IfElse-Conditional-Statement
	 */
	Tree makeIfElse(Token token, Tree cond, Tree trueStmt, Tree falseStmt);

	/**
	 * Building method, represents the highest tree level of an imported source
	 * file
	 * 
	 * @param mainClassName
	 *            Token-Array, that contains the name of the MainClass of the
	 *            program, e.g.: MainClass: A.b.C; -> [A,b,C]
	 * @param importFiles
	 *            Map that contains String representation of an import (the
	 *            filename) as well as the representing Tree, usually a
	 *            ImportTree
	 * @param classes
	 *            array of trees representing all classes, interfaces, etc.
	 *            contained by the current imported source-code-file
	 * @return the root node of an import
	 */
	Tree makeImport(Token[] mainClassName, Map<String, Tree> importFiles,
			Tree... classes);

	/**
	 * Building method, created tree represents an input expression. SO-Code:
	 * in(float);
	 * 
	 * @param token
	 *            token represents the input-token, TokenType.IN
	 * @param typ
	 *            type representing the type the input will be casted to
	 * @return a node representing an input expression
	 */
	Tree makeInput(Token token, Type typ);

	/**
	 * Building method, represents the root node of an interface declaration
	 * 
	 * @param token
	 *            the token that represents the name of the interface
	 * @param numberOfType
	 *            unique number identifying a class or an interface
	 * @param extendsArray
	 *            array of reference-types, the interfaces inherits from // @sebastian
	 *            "interfacES" but "inheritS" think it should be one interface
	 *            (compare makeClassDecl)
	 * @param body
	 *            tree representing the body of an interface-declaration
	 * @return the root node of an interface declaration
	 */
	Tree makeInterfaceDecl(Token token, int numberOfType, Type[] extendsArray,
			Tree body);

	/**
	 * Building Method, represents an length-expression, usually something like:
	 * b.c.length;
	 * 
	 * @param token
	 *            the token, representing this expression, usually length
	 * @param ident
	 *            the token that represents the name of the array, this
	 *            expression returns the length of
	 * @param left
	 *            , may be null, tree that represents the path to this
	 *            object/array
	 * @return the tree representing the length expression
	 */
	Tree makeLengthExpr(Token token, Token ident, Tree left);

	/**
	 * Building method, tree only represents a list of trees. It is an
	 * artificial tree and has little to do with the syntactic structure of the
	 * program. Therefore it only has an artificial token with the
	 * TokenType.LIST.
	 * 
	 * @param nodes
	 *            trees combined into one tree
	 * @return a tree representing a list of trees
	 */
	Tree makeList(Tree... nodes);

	/**
	 * Building method, creates a node, representing a simple literal
	 * 
	 * @param token
	 *            representing the literal, e.g.: integer, floating point
	 *            number, string ...
	 * @return a node representing a literal
	 */
	Tree makeLiteral(Token token);

	/**
	 * creates node, representing the access of a local array. local here means
	 * the array is only available within the method (in best case) and is not a
	 * field of a class.
	 * 
	 * @param token
	 *            token representing the name of the local array
	 * @param indexList
	 *            list of trees representing the indices of the field of the
	 *            array to access
	 * @return a subtree representing the access of a local array
	 */
	Tree makeLocalArrayAccess(Token token, List<Tree> indexList);

	/**
	 * Building method, created tree represents the access of a local variable.
	 * local here means the variable is only available within the method (in
	 * best case), it is declared.
	 * 
	 * @param token
	 *            token representing the name of the local variable to access
	 *            here
	 * @return a node representing the local variable access
	 */
	Tree makeLocalVarAccess(Token token);

	/**
	 * creates node, representing the declaration of a method with following
	 * attitudes (e.g: modifiers, type, parameters, etc.)
	 * 
	 * @param modifierList
	 *            list of modifiers limiting the accessibility of the method and
	 *            giving special attitudes, e.g.: static methods can be called
	 *            everywhere.
	 * @param token
	 *            token representing the name of the method
	 * @param type
	 *            type specifying the type of the returned value
	 * @param params
	 *            tree representing the list of needed parameters (ListTree)
	 * @param throwsList
	 *            list of types (of exceptions) that can be thrown during the
	 *            execution of the method
	 * @param body
	 *            tree representing the body of the method. the body will be
	 *            executed with the given arguments when the method is called
	 * @param localMethodVar
	 *            unique identifying number, needed for code generation. Number
	 *            is unique in the complete source file.
	 * @return subtree representing the declaration of a method
	 */
	Tree makeMethodDeclaration(List<Modifiers> modifierList, Token token,
			Type type, Tree params, List<Type> throwsList, Tree body,
			int localMethodVar);

	/**
	 * Building Method, created node represents the header of a method. This
	 * tree is needed, e.g.: to declare method-signatures in an interface. Thus
	 * the method has no real body. The method-header gives a the signature, a
	 * certain method in a class (implementing the interface) has to fulfil.
	 * 
	 * @param modifierList
	 *            list of modifiers which limit the accessibility of the method
	 *            or change attitude (static).
	 * @param token
	 *            token that represents the name of the method
	 * @param type
	 *            type of the value to be returned after body execution
	 * @param params
	 *            tree representing the list of parameters a concrete
	 *            implementation of this method will need
	 * @param throwsList
	 *            list of types (exception-classes) specifying all possibilities
	 *            of exceptions that can be thrown during execution
	 * @return a node representing the header of a method (e.g.: interfaces)
	 */
	Tree makeMethodHeader(List<Modifiers> modifierList, Token token, Type type,
			Tree params, List<Type> throwsList);

	/**
	 * creates a subtree that represents the invocation of a method of a certain
	 * class. The method must be part of the class, the leftHandObjectPath is
	 * object of.
	 * 
	 * @param token
	 *            token, representing the name of method to be invoked
	 * @param leftHandObjectPath
	 *            tree representing the object-path you have to follow to find
	 *            the method.
	 * @param arguments
	 *            array of trees, one tree represents one argument to be given
	 *            to the method. The order of arguments is kept.
	 * @return a node representing a method-invocation tree
	 */
	Tree makeMethodInvocation(Token token, Tree leftHandObjectPath,
			Tree[] arguments);

	/**
	 * Building method, created tree represents the invocation of a static
	 * method within the class, the code-sequence calling the method. That only
	 * means you call a static local method. So you don't need a argument
	 * "this".
	 * 
	 * @param tok
	 *            token representing the name of the method to be called
	 * @param arguments
	 *            array of trees, representing the arguments the method gets
	 *            (not this)
	 * @return a node representing the invocation of a static local method
	 */
	Tree makeMethodInvocationStaticWithinOwnClass(Token tok, Tree[] arguments);

	/**
	 * creates a subtree representing the creation of a new array, e.g.: new
	 * int[8][9]. In this special case it is going to be an 8 x 9 matrix
	 * 
	 * @param token
	 *            token representing the creation, TokenType.NEW
	 * @param ty
	 *            representing the type each field of the array will have, here:
	 *            int
	 * @param arrayBounces
	 *            list of trees, representing the bounces of the array, here 8
	 *            and 9
	 * @return a node representing the creation of an array
	 */
	Tree makeNewArray(Token token, Type ty, List<Tree> arrayBounces);

	/**
	 * creates a node representing an output statement; SO-Code: out(8) [prints
	 * 8 on the command line]
	 * 
	 * @param token
	 *            token representing the output statement, TokenType.OUT
	 * @param expr
	 *            tree representing the output, here LiteralTree (8)
	 * @return a subtree representing an output statement
	 */
	Tree makeOutput(Token token, Tree expr);

	/**
	 * Building method, created tree represents a post (returns value before
	 * increasing, decreasing) increment or decrement expression or statement,
	 * e.g.: i++ or i--
	 * 
	 * @param token
	 *            token representing decrement or increment token,
	 *            TokenType.INCREMENT, TokenType.DECREMENT
	 * @param expr
	 *            tree representing the term to be increased or decreased, here
	 *            "i"
	 * @return a node representing a post increment/decrement
	 *         statement/expression
	 */
	Tree makePostIncDec(Token token, Tree expr);

	/**
	 * Building method, created tree represents a pre (returns value after
	 * increasing, decreasing) increment or decrement expression or statement,
	 * e.g.: ++i or --i
	 * 
	 * @param token
	 *            token representing decrement or increment token,
	 *            TokenType.INCREMENT, TokenType.DECREMENT
	 * @param expr
	 *            tree representing the term to be increased or decreased, here
	 *            "i"
	 * @return a node representing a pre increment/decrement
	 *         statement/expression
	 */
	Tree makePreIncDec(Token token, Tree expr);

	/**
	 * Building method, represents also the highest tree level, the root node
	 * 
	 * @param mainClassName
	 *            Token-Array, that contains the name of the MainClass of the
	 *            program, e.g.: MainClass: A.b.C; -> [A,b,C]
	 * @param importFiles
	 *            Map that contains String representation of an import (the
	 *            filename) as well as the representing Tree, usually a
	 *            ImportTree
	 * @param classes
	 *            array of trees representing all classes, interfaces, etc.
	 *            contained by the current source-code-file
	 * @return the root node of the program
	 */
	Tree makeProgram(Token[] mainClassName, Map<String, Tree> importFiles,
			Tree... classes);

	/**
	 * creates a node, representing a return-statement
	 * 
	 * @param token
	 *            return-token, TokenType.RETURN
	 * @param expr
	 *            expression that has to be returned in the SO-code
	 * @return a node representing a return-Expression in SO
	 */
	Tree makeReturn(Token token, Tree expr);

	/**
	 * Building method, created tree represents a static initialisation at the
	 * beginning of program execution. This is needed, e.g. to initialise the
	 * static values of a class. Therefore it must be the first code-sequence in
	 * a class. Only static fields or methods are available. SO-Code: static {
	 * ... }
	 * 
	 * @param token
	 *            token representing the static block, TokenType.STATIC
	 * @param block
	 *            tree representing the code to be executed at the beginning of
	 *            the program
	 * @return a node representing a static initialisation block
	 */
	Tree makeStaticInitializer(Token token, Tree block);

	/**
	 * Building method, created tree represents the beginning of an access of a
	 * field or method in a superclass. SO-Code: super(A). ...
	 * 
	 * @param token
	 *            token representing the access of a specified superclass,
	 *            TokenType.SUPER
	 * @param ty
	 *            type specifying the superclass to access, here "A"
	 * @return a node representing the access of the superclass
	 */
	Tree makeSuperAccess(Token token, Type ty);

	/**
	 * Building method, created subtree represents a switch statement. A switch
	 * statement allows to compare a given expression with some patterns,
	 * compare with pattern matching in functional programming languages like
	 * ML.
	 * 
	 * @param token
	 *            token representing the beginning of the switch-statement,
	 *            TokenType.SWITCH
	 * @param expr
	 *            tree representing the expression to compare
	 * @param body
	 *            tree representing the body of the switch statement, consisting
	 *            of switch-groups (compare with
	 *            {@link tree.TreeFactory#makeSwitchGroup(Token, Tree, Tree)}
	 * @return a node representing a switch statement
	 */
	Tree makeSwitch(Token token, Tree expr, Tree body);

	/**
	 * created a node representing a switch-group. SO-Code: case 5: .... case 6:
	 * .... default: .... [three groups]
	 * 
	 * @param token
	 *            token representing the beginning of the switch-group,
	 *            TokenType.CASE or TokenType.DEFAULT
	 * @param expr
	 *            tree representing the expression to compare with, in case of
	 *            TokenType.DEFAULT the expr-tree is the null-reference
	 * @param blockStatementList
	 *            a ListTree representing a list of statements being executed if
	 *            the expr matches
	 * @return a subtree representing a switch group
	 */
	Tree makeSwitchGroup(Token token, Tree expr, Tree blockStatementList);

	/**
	 * Building method, created tree represents the access of the this-pointer.
	 * With this pointer you can access all methods and fields in a class. This
	 * pointer will be an argument, when you call a method. It is a kind of
	 * self-reference.
	 * 
	 * @param token
	 *            token representing the this-access, TokenType.THIS
	 * @return a node representing a this-access
	 */
	Tree makeThisAccess(Token token);

	/**
	 * Building method, created subtree represents a throw statement. This
	 * statement throws an specified exception.
	 * 
	 * @param token
	 *            token representing the throw-statement, TokenType.THROW
	 * @param expr
	 *            tree specifying the exception to throw, this can be a
	 *            field-access in case of a static exception or a
	 *            class-instance-creation in most of the cases
	 * @return a node representing a throw-exception
	 */
	Tree makeThrowException(Token token, Tree expr);

	/**
	 * creates a node, representing a try-statement (see also catch-block)
	 * 
	 * @param token
	 *            identifies this block as try-statement
	 * @param tryBlock
	 *            block representing the code to try executing
	 * @param catchTree
	 *            block representing the case an exception is thrown
	 * @param finallyBlock
	 *            block representing the code to execute at the end, no matter
	 *            if an exception is thrown
	 * @return node, representing a try-statement
	 */
	Tree makeTry(Token token, Tree tryBlock, Tree catchTree, Tree finallyBlock);

	/**
	 * creates a node, representing an unary operator
	 * 
	 * @param token
	 *            identification of the operator
	 * @param op
	 *            the expression, the operator modifies
	 * @return a node, representing a unary operation
	 */
	Tree makeUnOp(Token token, Tree op);

	/**
	 * creates a node, representing a while-loop
	 * 
	 * @param token
	 *            while-loop-Token, TokenType.WHILE
	 * @param cond
	 *            as long as this evaluates to true, the loop runs
	 * @param body
	 *            this body has to be repeated as long as the condition allows
	 *            it
	 * @return a node representing a while-loop
	 */
	Tree makeWhile(Token token, Tree cond, Tree body);

}
